/**
 * @file bsp_spi.c
 * @brief SPI驱动实现 - H743-V2飞控板
 * @author Flight Control Team
 * @date 2025-11-09
 *
 * 硬件配置参考: reference_firmware/h743_v2_pin_analysis.md
 *
 * SPI2配置:
 *   - 时钟源: PLL2_P = 96MHz
 *   - 波特率: 96MHz / 16 = 6MHz (BMI088最大10MHz)
 *   - 模式: Mode 3 (CPOL=1, CPHA=1)
 *   - 数据位: 8位
 *   - MSB先行
 *
 * SPI3配置:
 *   - 时钟源: PLL2_P = 96MHz
 *   - 波特率: 96MHz / 8 = 12MHz (BMI270最大10MHz)
 *   - 模式: Mode 0 (CPOL=0, CPHA=0) - BMI270要求！
 *   - 数据位: 8位
 *   - MSB先行
 */

#include "bsp_spi.h"
#include <string.h>

/* SPI句柄 */
static SPI_HandleTypeDef hspi2;  /* BMI088 */
static SPI_HandleTypeDef hspi3;  /* BMI270 */

/* 初始化状态 */
static SPI_Status_t spi_status = {0};

/**
 * @brief SPI2 GPIO初始化
 */
static void BSP_SPI2_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* 使能GPIO时钟 */
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();

    /* 配置SPI2引脚: SCK(PD3), MISO(PC2), MOSI(PC3) */

    /* SCK: PD3, AF5, 2MHz转换率（参考固件配置） */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;  /* 2MHz转换率 */
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* MISO: PC2, AF5, 高速 */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* MOSI: PC3, AF5, 高速 */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* 配置片选引脚: CS_ACCEL(PD4), CS_GYRO(PD5) */
    GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* 片选默认拉高（未选中） */
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_SET);  /* CS_ACCEL */
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_SET);  /* CS_GYRO */

    /* 配置数据就绪引脚: DRDY_ACCEL(PC14), DRDY_GYRO(PC15) */
    /* 注意: 这里只配置为输入，中断配置在传感器驱动中完成 */
    GPIO_InitStruct.Pin = GPIO_PIN_14 | GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;  /* 浮空输入 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

/**
 * @brief SPI3 GPIO初始化
 */
static void BSP_SPI3_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* 使能GPIO时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();

    /* 配置SPI3引脚: SCK(PB3), MISO(PB4), MOSI(PD6) */

    /* SCK: PB3, AF6, 2MHz转换率 */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;  /* 2MHz转换率 */
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* MISO: PB4, AF6, 高速 */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* MOSI: PD6, AF5, 高速 */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI3;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* 配置片选引脚: CS(PA15) */
    GPIO_InitStruct.Pin = GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* 片选默认拉高（未选中） */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);

    /* 配置数据就绪引脚: DRDY(PB7) */
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;  /* 浮空输入 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**
 * @brief SPI2初始化 (BMI088)
 */
int BSP_SPI2_Init(void)
{
    /* 使能SPI2时钟 */
    __HAL_RCC_SPI2_CLK_ENABLE();

    /* 初始化GPIO */
    BSP_SPI2_GPIO_Init();

    /* 配置SPI2参数 */
    hspi2.Instance = SPI2;
    hspi2.Init.Mode = SPI_MODE_MASTER;                      /* 主机模式 */
    hspi2.Init.Direction = SPI_DIRECTION_2LINES;            /* 全双工 */
    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;                /* 8位数据 */
    hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;             /* CPOL=1 (Mode 3) */
    hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;                  /* CPHA=1 (Mode 3) */
    hspi2.Init.NSS = SPI_NSS_SOFT;                          /* 软件片选 */
    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;  /* PLL2_P 80MHz/8 = 10MHz (与PX4一致) */
    hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;                 /* MSB先行 */
    hspi2.Init.TIMode = SPI_TIMODE_DISABLE;                 /* 禁用TI模式 */
    hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; /* 禁用CRC */
    hspi2.Init.CRCPolynomial = 7;
    hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
    hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
    hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
    hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;

    if (HAL_SPI_Init(&hspi2) != HAL_OK) {
        return -1;
    }

    spi_status.spi2_initialized = 1;
    return 0;
}

/**
 * @brief SPI3初始化 (BMI270)
 * 注意：BMI270使用SPI Mode 0 (CPOL=0, CPHA=0)，与BMI088的Mode 3不同！
 */
int BSP_SPI3_Init(void)
{
    /* 使能SPI3时钟 */
    __HAL_RCC_SPI3_CLK_ENABLE();

    /* 初始化GPIO */
    BSP_SPI3_GPIO_Init();

    /* 配置SPI3参数 - BMI270使用Mode 0！ */
    hspi3.Instance = SPI3;
    hspi3.Init.Mode = SPI_MODE_MASTER;
    hspi3.Init.Direction = SPI_DIRECTION_2LINES;
    hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;              /* CPOL=0 (Mode 0) - BMI270要求！ */
    hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;                  /* CPHA=0 (Mode 0) - BMI270要求！ */
    hspi3.Init.NSS = SPI_NSS_SOFT;
    hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;  /* PLL2_P 80MHz/8 = 10MHz (与PX4一致) */
    hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi3.Init.CRCPolynomial = 7;
    hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
    hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    hspi3.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi3.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
    hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
    hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;

    if (HAL_SPI_Init(&hspi3) != HAL_OK) {
        return -1;
    }

    spi_status.spi3_initialized = 1;
    return 0;
}

/**
 * @brief 初始化所有SPI总线
 */
int BSP_SPI_Init(void)
{
    int ret = 0;

    /* 初始化SPI2 (BMI088) */
    if (BSP_SPI2_Init() != 0) {
        ret = -1;
    }

    /* 初始化SPI3 (BMI270) */
    if (BSP_SPI3_Init() != 0) {
        ret = -1;
    }

    return ret;
}

/**
 * @brief BMI088片选控制
 */
void BSP_SPI_BMI088_CS(BMI088_Device_t device, uint8_t select)
{
    GPIO_PinState state = select ? GPIO_PIN_RESET : GPIO_PIN_SET;

    if (device == BMI088_ACCEL) {
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, state);  /* PD4: CS_ACCEL */
    } else if (device == BMI088_GYRO) {
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, state);  /* PD5: CS_GYRO */
    }
}

/**
 * @brief BMI270片选控制
 */
void BSP_SPI_BMI270_CS(uint8_t select)
{
    GPIO_PinState state = select ? GPIO_PIN_RESET : GPIO_PIN_SET;
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, state);  /* PA15: CS */
}

/**
 * @brief SPI传输（阻塞模式）
 */
int BSP_SPI_Transfer(SPIPort_t port, const uint8_t *tx_data, uint8_t *rx_data, uint16_t len)
{
    HAL_StatusTypeDef status;
    SPI_HandleTypeDef *hspi;

    /* 参数检查 */
    if (len == 0) {
        return -1;
    }

    /* 选择SPI端口 */
    if (port == SPI_PORT_2) {
        if (!spi_status.spi2_initialized) {
            return -1;
        }
        hspi = &hspi2;
    } else if (port == SPI_PORT_3) {
        if (!spi_status.spi3_initialized) {
            return -1;
        }
        hspi = &hspi3;
    } else {
        return -1;
    }

    /* 执行SPI传输 */
    if (tx_data != NULL && rx_data != NULL) {
        /* 全双工传输 */
        status = HAL_SPI_TransmitReceive(hspi, (uint8_t *)tx_data, rx_data, len, 100);
    } else if (tx_data != NULL) {
        /* 只发送 */
        status = HAL_SPI_Transmit(hspi, (uint8_t *)tx_data, len, 100);
    } else if (rx_data != NULL) {
        /* 只接收 */
        status = HAL_SPI_Receive(hspi, rx_data, len, 100);
    } else {
        return -1;
    }

    return (status == HAL_OK) ? 0 : -1;
}

/**
 * @brief SPI读取单个寄存器
 */
int BSP_SPI_ReadReg(SPIPort_t port, uint8_t reg, uint8_t *data)
{
    uint8_t tx_buf[3];
    uint8_t rx_buf[3];

    /* BMI088加速度计读操作: 寄存器地址 | 0x80, 然后是2个dummy字节
     * 参考：BMI088数据手册 6.1.2 SPI interface of accelerometer part
     * "the requested data is not sent immediately, but instead first a dummy byte is sent"
     */
    tx_buf[0] = reg | 0x80;  /* 读标志 */
    tx_buf[1] = 0x00;        /* dummy字节1 */
    tx_buf[2] = 0x00;        /* dummy字节2 */

    if (BSP_SPI_Transfer(port, tx_buf, rx_buf, 3) != 0) {
        return -1;
    }

    *data = rx_buf[2];  /* 第三个字节是有效数据 */
    return 0;
}

/**
 * @brief SPI写入单个寄存器
 */
int BSP_SPI_WriteReg(SPIPort_t port, uint8_t reg, uint8_t data)
{
    uint8_t tx_buf[2];
    uint8_t rx_buf[2];

    /* BMI088写操作: 寄存器地址 & 0x7F, 然后写入数据 */
    tx_buf[0] = reg & 0x7F;  /* 写标志（bit7=0） */
    tx_buf[1] = data;

    return BSP_SPI_Transfer(port, tx_buf, rx_buf, 2);
}

/**
 * @brief SPI读取多个寄存器（用于BMI088加速度计）
 * 注意：BMI088加速度计需要dummy字节，传输序列为：地址 + dummy + 数据
 */
int BSP_SPI_ReadRegs(SPIPort_t port, uint8_t reg, uint8_t *data, uint16_t len)
{
    uint8_t tx_buf[32];
    uint8_t rx_buf[32];
    uint16_t i;

    /* 检查长度 */
    if (len > 29) {  /* 预留3字节给地址、dummy和数据起始 */
        return -1;
    }

    /* 准备发送缓冲区：地址 + dummy + len个数据字节 */
    tx_buf[0] = reg | 0x80;  /* 读标志 */
    tx_buf[1] = 0x00;        /* dummy字节 */
    for (i = 2; i < len + 2; i++) {
        tx_buf[i] = 0x00;  /* 数据占位字节 */
    }

    /* 执行传输：总共 len + 2 个字节 */
    if (BSP_SPI_Transfer(port, tx_buf, rx_buf, len + 2) != 0) {
        return -1;
    }

    /* 复制数据（跳过前两个字节：地址和dummy） */
    memcpy(data, &rx_buf[2], len);
    return 0;
}

/**
 * @brief 获取SPI初始化状态
 */
void BSP_SPI_GetStatus(SPI_Status_t *status)
{
    if (status != NULL) {
        *status = spi_status;
    }
}

